#导入库
import numpy as np
from PIL import Image
import cv2
import numpy as np
import matplotlib.pyplot as plt
import math as math

# 加载图像
img = cv2.imread("image.jpg")

#创建一个数组，该数组转化为图片后为全白
img =255*np.ones((640, 640), dtype=np.uint8)

# DDA算法的函数
def DDA(x0, y0, x1, y1):
    # 计算斜率和截距
    k = (y1 - y0) / (x1 - x0)   
    #计算常数b
    b = y0 - k * x0
    # 从x0开始，每次增加1，计算y
    x = x0
    #开启一个到x1循环
    while x <= x1:
        #求出y
        y = k * x + b
        # 对x和y进行四舍五入
        x = round(x)
        y = round(y)
        # 绘制像素点
        img[x][y]=200
        #通过对于所求的x,y坐标进行p1、p2、p3的轮流变换后，得到一个左移15，缩小0.75倍，旋转30度的x，y坐标，再把所有的点都这样变换后可以使整个图形变换。
        p1 = rotate(x, y, math.pi/6, 40, 280)
        p2 = translate(int(p1[0]),int(p1[1]), 0, -15)
        p3 = scale(int(p2[0]), int(p2[1]), 0.75, 0.75, 0, 0)
        img[int(p3[0])][int(p3[1])] = 0
        # x增加1
        x = x + 1
        
# 对换
def change(x, y):
    x, y = y, x
    return x, y

# 中点直线扫描转换算法
def midPoint(x1, y1, x2, y2):
    # 计算斜率
    dx = abs(x2 - x1)
    dy = abs(y2 - y1)
    k = dy / dx
    # 判断斜率是否大于1，如果大于1则需要反转x和y
    if (k < 1):
        #求出中点判别式的值
        d = 2 * dy - dx
        #给xy赋值x1y1
        x = x1
        y = y1
        #xy处为黑点
        img[x][y]=0
        #循环到x=x2-1
        while x < x2:
            #d<0 则为xy点为黑点
            if d < 0:
                d = d + 2 * dy
            #d>=0 则为x y+1处为黑点
            else:
                d = d + 2 * (dy - dx)
                y = y + 1
            x = x + 1
            img[x][y]=200
             #通过对于所求的x,y坐标进行p1、p2、p3的轮流变换后，得到一个左移15，缩小0.75倍，旋转30度的x，y坐标，再把所有的点都这样变换后可以使整个图形变换。
            p1 = rotate(x, y, math.pi/6, 40, 280)
            p2 = translate(int(p1[0]),int(p1[1]), 0, -15)
            p3 = scale(int(p2[0]), int(p2[1]), 0.75, 0.75, 0, 0)
            img[int(p3[0])][int(p3[1])] = 0
    #k>1 则反转xy来进行同一个过程
    else:
        d = 2 * dx - dy
        x = x1
        y = y1
        img[x][y]=200
         #通过对于所求的x,y坐标进行p1、p2、p3的轮流变换后，得到一个左移15，缩小0.75倍，旋转30度的x，y坐标，再把所有的点都这样变换后可以使整个图形变换。
        p1 = rotate(x, y, math.pi/6, 40, 280)
        p2 = translate(int(p1[0]),int(p1[1]), 0, -15)
        p3 = scale(int(p2[0]), int(p2[1]), 0.75, 0.75, 0, 0)
        img[int(p3[0])][int(p3[1])] = 0
        while y < y2:
            #d<0 xy为黑点，d>0 x+1 y为黑点
            if d < 0:
                d = d + 2 * dx
            else:
                d = d + 2 * (dx - dy)
                x = x + 1
            y = y + 1
            img[x][y]=200
             #通过对于所求的x,y坐标进行p1、p2、p3的轮流变换后，得到一个左移15，缩小0.75倍，旋转30度的x，y坐标，再把所有的点都这样变换后可以使整个图形变换。
            p1 = rotate(x, y, math.pi/6, 40,280)
            p2 = translate(int(p1[0]),int(p1[1]), 0, -15)
            p3 = scale(int(p2[0]), int(p2[1]), 0.75, 0.75, 0, 0)
            img[int(p3[0])][int(p3[1])] = 0

#bresemham画圆
def Br_Circle(img,x0 , y0 , r):
    #给予x一个初值0
    x = 0
    #y等于半径r
    y = r
    #对flag判别赋值2-2r
    flag = 2 - 2*r
    #通过对称1个点绘制4个点
    img[x + x0, y + y0] = 0
    img[x + x0, -y + y0] = 0
    img[-x + x0, y + y0] = 0
    img[-x + x0, -y + y0] = 0
    #循环到y=0为止,即绘画一个四分之一圆
    while y > 0:
        #判别式小于0则 判别式flag1=2flag+2y-1 
        if flag < 0:
            #判别圆内两点
            flag1 = 2 * (flag + y) - 1
            #通过flag1来判别圆内两点选择哪一个
            if flag1 <= 0:
                Direction = 1
            else:
                Direction = 2
        #判别式大于0则 判别式flag2=2flag-2x-1
        if flag > 0:
            #判别圆外两点的判别式
            flag2 = 2 * (flag - x) - 1
            #通过flag2来判别圆外两点选择
            if flag2 <= 0:
                Direction = 2
            else:
                Direction = 3
        #就在圆上直接选择
        if flag == 0:
            Direction = 2
        #位置一 正右边 
        if Direction == 1:
            x +=1
            flag +=2 * x + 1
        #位置二 右下
        if Direction == 2:
            x += 1
            y -= 1
            flag +=2 * x - 2 * y + 2
        #位置三 正下
        if Direction == 3:
            y -=1
            flag +=1 - 2 * y

        #原始位置
        img[x + x0, y + y0] = 200
        img[x + x0, -y + y0] = 200
        img[-x + x0, y + y0] = 200
        img[-x + x0, -y + y0] = 200
        
        #通过对于所求的x,y坐标进行旋转平移缩放的轮流变换后，得到一个左移15，缩小0.75倍，旋转30度的x，y坐标，再把所有的点都这样变换后可以使整个图形变换。
        p1 = translate(x, y, 0, -15)
        p2 = translate(x, y, 0, 15)
        p3 = scale(int(p2[0]), int(p2[1]), 0.75, 0.75, 0, 0)
        p4 = scale(int(p1[0]), int(p1[1]), 0.75, 0.75, 0, 0)

        #旋转平移后的位置
        img[int(p1[0]) + x0, int(p1[1]) + y0] =  200
        img[int(p2[0]) + x0, -int(p2[1]) + y0] = 200
        img[-int(p1[0]) + x0, int(p1[1]) + y0] = 200
        img[-int(p2[0]) + x0, -int(p2[1]) + y0] =200
        

        #通过对称性,用四分之一圆绘画出整圆
        #最终位置
        img[int(p4[0]) + x0, int(p4[1]) + y0] = 0
        img[int(p3[0]) + x0, -int(p3[1]) + y0] = 0
        img[-int(p4[0]) + x0, int(p4[1]) + y0] = 0
        img[-int(p3[0]) + x0, -int(p3[1]) + y0] = 0


# 旋转
# @param x: x坐标
# @param y: y坐标
# @param theta: 旋转角度
# @param x0: 旋转中心x坐标
# @param y0: 旋转中心y坐标
def rotate(x, y, theta, x0, y0):
    t0 = x
    t1 = y

    x1 = t0 * math.cos(theta) - t1 * math.sin(theta) + x0 * (1 - math.cos(theta)) + y0 * math.sin(theta)
    y1 = t0 * math.sin(theta) + t1 * math.cos(theta) + y0 * (1 - math.cos(theta)) - x0 * math.sin(theta)

    return [x1, y1]


# 平移变换
# @param x: x坐标
# @param y: y坐标
# @param dx: x方向平移距离
# @param dy: y方向平移距离
def translate(x, y, dx, dy):
    x1 = x + dx
    y1 = y + dy

    return [x1, y1]

# 缩放
# @param x: x坐标
# @param y: y坐标
# @param sx: x方向缩放比例
# @param sy: y方向缩放比例
# @param x0: 缩放中心x坐标
# @param y0: 缩放中心y坐标
def scale(x, y, sx, sy, x0, y0):
    t0 = x
    t1 = y

    x1 = sx * t0 + x0 * (1 - sx)
    y1 = sy * t1 + y0 * (1 - sy)

    return [x1, y1]

#画两圈圆
Br_Circle(img,130 , 160 , 100)
Br_Circle(img,130,160,95)

#上第一条水平线
midPoint(90,80,90.1,240)
#上左第二条水平线
midPoint(110,100,110.1,145)
#上右第二条水平线
midPoint(110,175,110.1,220)
#上左第三条水平线
midPoint(120,110,120.1,145)
#上左第四条水平线
midPoint(140,130,140.1,145)
#上右第三条水平线
midPoint(140,175,140.1,230)
#上右第四条水平线
midPoint(160,185,160.01,205)

#左第一条斜线
midPoint(90,80,110,100)
#右第一条斜线
DDA(90,240,110,220)
#左第二条斜线
midPoint(120,110,140,130)
#右第二条斜线
DDA(140,230,160,205)

#左第一条竖线
midPoint(110,145,120,145)
#左第二条竖线
midPoint(140,145,200,145)
#右第一条竖线
midPoint(110,175,140,175)
#底部斜线
DDA(160,185,200,145)

#内部左一斜线
DDA(90,175,110,145)

# 把修改后的数组转换为图片
im = Image.fromarray(img)

# 显示图片
im.show()
